package com.witframework.soa.transform;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.witframework.WitException;
import com.witframework.soa.util.ClassTypeUtil;
import com.witframework.util.StringDigest;

/**
 * 将XML文档转换为bean
 * 如果目标对象的类型和原始的类型不一致，首先应将目标对象使用的类型注册。
 * @author wuxinyang
 *
 */
public class XmlToBean {
	
	private Map<String, String> typeMap=new HashMap<String, String>();
	private boolean noCustomType=false;
	/**
	 * 注册类型映射
	 * 转换时会将这里注册的类型映射到目标对象
	 * @param sourceType
	 * @param targetType
	 */
	public void registerTypeMap(String sourceType,String targetType){
		typeMap.put(sourceType, targetType);
	}
	public Object parseNoCustomType(String xml){
		noCustomType=true;
		return parse(xml);
	}
	/**
	 * 执行转换
	 * @param xml -对象的xml文档表示
	 * @return bean xml表示的bean对象 
	 * @throws Exception
	 */
	public Object parse(String xml){
		InputStream isXML=new ByteArrayInputStream(xml.getBytes());			
		try {
			return parseFromInputStream(isXML);
		} catch (Exception e) {
			throw new WitException(e);
		}
	}
	/**
	 * 执行转换
	 * @param inputStream -对象的xml输入流
	 * @return bean xml表示的bean对象 
	 * @throws Exception
	 */
	public Object parseFromInputStream(InputStream inputStream) throws Exception{
		Document doc=DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
		Node root=doc.getFirstChild();	
		if(root.getNodeName().equals("bean")){
			NodeList mapping=root.getChildNodes().item(1).getChildNodes();
			for(int i=0;i<mapping.getLength();i++){
				Node map=mapping.item(i);
				registerTypeMap(map.getAttributes().getNamedItem("key").getNodeValue(),map.getAttributes().getNamedItem("type").getNodeValue());
			}
			return createBean(root.getChildNodes().item(0).getFirstChild());
		}else{
			return createBean(root);
		}
	}
	private Object createArray(NodeList nodes){		
		Object targetArray = null;
		Class elementType=Void.TYPE;
		if(nodes.getLength()>0){
			List list = new LinkedList();
			String elementTypeString= nodes.item(0).getAttributes().getNamedItem("type").getNodeValue();
			elementTypeString=getRegisterType(elementTypeString);
			if(ClassTypeUtil.isNumber(elementTypeString)){
				String[] values=nodes.item(0).getTextContent().split(",");
				elementType= ClassTypeUtil.getPrimitiveType(elementTypeString);
				for(int i=0;i<values.length;i++){
					list.add(ClassTypeUtil.createPrimitiveValue(values[i],elementTypeString));
				}
			}else if(ClassTypeUtil.isByte(elementTypeString)){
				//解码byte[]
				targetArray=StringDigest.decodeBytes(nodes.item(0).getTextContent());
			}			
			else{		
				if(ClassTypeUtil.isPrimitiveType(elementTypeString)||ClassTypeUtil.isBasePrimitiveType(elementTypeString)){
					elementType= ClassTypeUtil.getPrimitiveType(elementTypeString);
				}else if(noCustomType&&ClassTypeUtil.isCustomType(elementTypeString)){	
					elementType=java.util.HashMap.class;
				}
				else{
					elementType= ClassTypeUtil.newObject(elementTypeString).getClass();					
				}
		        for (int i = 0; i < nodes.getLength(); i++){
		        	Object value=createBean(nodes.item(i));
		        	list.add(value);
		        }
			}
			if(elementType!=Void.TYPE){
				Object[] objectArray = list.toArray ();
		        targetArray = Array.newInstance (elementType, objectArray.length);
		        for (int i = 0; i < objectArray.length; i++){
		            Array.set (targetArray, i, objectArray[i]);
		        }
			}
		}		
        return targetArray;
	}
	private Object createBean(Node node){
		String type=node.getAttributes().getNamedItem("type").getNodeValue();
		type=getRegisterType(type);
		if(ClassTypeUtil.isPrimitiveType(type)||ClassTypeUtil.isBasePrimitiveType(type)){
			return ClassTypeUtil.createPrimitiveValue(node.getTextContent(),type);
		}
		
		Object bean;
		if(noCustomType&&ClassTypeUtil.isCustomType(type)){			
			bean=new HashMap();			
		}else{
			bean=ClassTypeUtil.newObject(type);
		}
		
		NodeList propertyList=node.getChildNodes();
		for(int i=0;i<propertyList.getLength();i++){
			Node property=propertyList.item(i);
			String propertyTypeString=property.getAttributes().getNamedItem("type").getNodeValue();
			Object propertyValue;
			if(ClassTypeUtil.isPrimitiveType(propertyTypeString)){
				propertyValue=ClassTypeUtil.createPrimitiveValue(property.getTextContent(),propertyTypeString);				
			}else if(isArrays(propertyTypeString)){				
				propertyValue=createArray(property.getChildNodes());				
			}else{
				propertyValue=createBean(property);
			}			
			ClassTypeUtil.setBeanPropertyValue(bean,property.getNodeName(),propertyValue);
		}
		return bean;
	}
	
	private boolean isArrays(String typeString){
		return typeString.equals("arrays");
	}
	
	private String getRegisterType(String type){
		String mappingType=typeMap.get(type);
		return mappingType!=null?mappingType:type;
	}
	
	
}
